﻿using CleanArchitecture.Core;
using CleanArchitecture.Core.Configuration;
using CleanArchitecture.Core.Handlers;
using CleanArchitecture.Core.Helper;
using CleanArchitecture.Core.Http;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Infrastructure.ActiveLogExtension;
using CleanArchitecture.Infrastructure.AutoMapper;
using CleanArchitecture.Infrastructure.Entities;
using CleanArchitecture.Infrastructure.Entities.AdminUsers;
using CleanArchitecture.Infrastructure.Entities.Business;
using CleanArchitecture.Infrastructure.Entities.Common;
using CleanArchitecture.Infrastructure.Entities.Settings;
using CleanArchitecture.Infrastructure.Interfaces;
using CleanArchitecture.Infrastructure.Interfaces.AdminUsers;
using CleanArchitecture.Infrastructure.Interfaces.Business;
using CleanArchitecture.Infrastructure.Interfaces.Common;
using CleanArchitecture.Infrastructure.Interfaces.Media;
using CleanArchitecture.Infrastructure.Interfaces.Security;
using CleanArchitecture.Infrastructure.Interfaces.SystemLog;
using CleanArchitecture.Infrastructure.Interfaces.SystemManage;
using CleanArchitecture.Infrastructure.Models;
using CleanArchitecture.Infrastructure.Models.Business.Advertises;
using CleanArchitecture.Infrastructure.Models.Business.Blog;
using CleanArchitecture.Infrastructure.Models.Business.Columns;
using CleanArchitecture.Infrastructure.Models.Business.Comments;
using CleanArchitecture.Infrastructure.Models.Business.FileUpload;
using CleanArchitecture.Infrastructure.Models.Business.News;
using CleanArchitecture.Infrastructure.Models.SystemManage;
using CleanArchitecture.Infrastructure.Plugins.BaiduFanyiSDK;
using CleanArchitecture.Infrastructure.Services;
using CleanArchitecture.Infrastructure.Services.Extensions;
using CleanArchitecture.Web.Backend.BackendApi;
using CleanArchitecture.Web.Controllers.Backend.Business;
using CleanArchitecture.Web.Factories;
using Masuit.LuceneEFCore.SearchEngine;
using Masuit.LuceneEFCore.SearchEngine.Extensions;
using Masuit.LuceneEFCore.SearchEngine.Interfaces;
using Microsoft.AspNetCore.Mvc;
using PanGu;
using PanGu.HighLight;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CleanArchitecture.Web.Controllers.Backend.BackendApi
{
    public class DeleteFileInfo
    {
        public int NewsItemId { get; set; }
        public string FileIds { get; set; }
        public string FileUrls { get; set; }
        public string IdPropName { get; set; }
        public string UrlPropName { get; set; }
    }
    public class BackendBusinessApiController : BackendBusinessController
    {
        #region Field
        private readonly NowaConfig _nowaConfig;
        private readonly NewsSettings _newsSettings;
        private readonly BlogSettings _blogSettings;
        private readonly MediaSettings _mediaSettings;
        private readonly AdminAreaSettings _adminareaSettings;
        private readonly IWorkContext _workContext;
        private readonly INewsService _newsService;
        private readonly IBlogService _blogService;
        private readonly IColumnService _columnService;
        private readonly ICommentService _commentService;
        private readonly IDateTimeHelper _datetimeHelper;
        private readonly ILanguageService _languageService;
        private readonly IGenericAttributeService _gaService;
        private readonly IAdvertiseService _advertiseService;
        private readonly IFileUploadService _fileuploadService;
        private readonly IPermissionService _permissionService;
        private readonly IBusinessModelFactory _businessmodelFactory;
        private ISearchEngine<AppDbObjectContext> _cachedsearchEngine;
        private readonly ISystemManageModelFactory _systemmanageModelFactory;
        #endregion

        #region Ctor
        public BackendBusinessApiController(ISystemModuleService systemmoduleService,
           IWorkContext workContext,
           INewsService newsService,
           IBlogService blogService,
           IColumnService columnService,
           IDateTimeHelper datetimeHelper,
           ILanguageService languageService,
           IPermissionService permissionService,
           NowaConfig nowaConfig,
           MediaSettings mediaSettings,
           NewsSettings newsSettings,
           BlogSettings blogSettings,
           AdminAreaSettings adminareaSettings,
           IFileUploadService fileuploadService,
           IBusinessModelFactory businessmodelFactory,
           ISystemManageModelFactory systemmanageModelFactory,
           IGenericAttributeService genericattributeService,
           IAdvertiseService advertiseService,
           ICommentService commentService)
           : base(systemmoduleService,
                 workContext,
                 newsSettings,
                 blogSettings,
                 languageService,
                 fileuploadService,
                 permissionService,
                 businessmodelFactory,
                 genericattributeService,
                 systemmanageModelFactory)
        {
            this._fileuploadService = fileuploadService;
            this._permissionService = permissionService;
            this._languageService = languageService;
            this._datetimeHelper = datetimeHelper;
            this._columnService = columnService;
            this._nowaConfig = nowaConfig;
            this._workContext = workContext;
            this._blogSettings = blogSettings;
            this._newsSettings = newsSettings;
            this._mediaSettings = mediaSettings;
            this._adminareaSettings = adminareaSettings;
            this._businessmodelFactory = businessmodelFactory;
            this._systemmanageModelFactory = systemmanageModelFactory;
            this._newsService = newsService;
            this._blogService = blogService;
            this._gaService = genericattributeService;
            this._advertiseService = advertiseService;
            this._commentService = commentService;
        }
        #endregion

        #region ColumnManage Api
        /// <summary>
        /// 为兼容之前代码，增加查询默认字段layout
        /// 在栏目管理表格中展示栏目页面布局类型及名称
        /// DavidLee 2020/04/20新增对栏目树分类查询
        /// </summary>
        /// <param name="languageid"></param>
        /// <param name="layout"></param>
        /// <returns></returns>
        [Route(BackendApiRouteConfig.BackendLoadColumnTree)]
        public async Task<IActionResult> BackendLoadColumnTree(int languageid = 0, int columntype = 0, bool layout = false)
        {
            try
            {
                var ztrees = _businessmodelFactory.PrepareColumnItemTreeModel(languageid, columntype, layout);
                if (ztrees == null) throw new NowaException(ApiResponseMessages.NoColumnsFoundForLanguage);
                return SuccessJson("", ztrees);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// DavidLee 2020/07/31 增加栏目菜单权限控制，为避免与之前API调用冲突，增加按用户权限查询
        /// 栏目菜单接口
        /// </summary>
        /// <param name="languageid"></param>
        /// <param name="columntype"></param>
        /// <returns></returns>
        [Route(BackendApiRouteConfig.BackendLoadAuthorizedColumnTree)]
        public async Task<IActionResult> BackendLoadAuthorizedColumnTree(int languageid = 0, int columntype = 0)
        {
            try
            {
                if (columntype > 0 && Enum.IsDefined(typeof(EntityEnumConfig.ColumnType), columntype))
                {
                    var cType = CommonHelper.To<EntityEnumConfig.ColumnType>(columntype);
                    bool IsLoadAllColumnTree = false;
                    if (cType == EntityEnumConfig.ColumnType.NewsColumn && _newsSettings.Enabled && _newsSettings.ColumnAuthorize)
                        IsLoadAllColumnTree = false;
                    else if (cType == EntityEnumConfig.ColumnType.BlogColumn && _blogSettings.Enabled && _blogSettings.ColumnAuthorize)
                        IsLoadAllColumnTree = false;
                    else IsLoadAllColumnTree = true;

                    if (IsLoadAllColumnTree) return await BackendLoadColumnTree(languageid, columntype);
                }
                else throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var CurrentUser = _workContext.CurrentAdminUser;
                int[] userRoleIds = CurrentUser.GetAdminRoles().Select(r => r.Id).ToArray();
                var ztrees = _businessmodelFactory.PrepareAuthorizedColumnItemTreeModel(userRoleIds, languageid, columntype);
                if (ztrees == null) throw new NowaException(ApiResponseMessages.NoColumnsFoundForLanguage);
                return SuccessJson("", ztrees);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpPost(BackendApiRouteConfig.BackendUpdateColumn)]
        public async Task<IActionResult> BackendUpdateColumn([FromBody]ColumnItemModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    if (model.Id > 0 && model.Id == model.ParentId)
                        throw new NowaException(ApiResponseMessages.ColumnAssigntoParent);
                    if (model.Name.Length > 20)
                        throw new NowaException(string.Format(ApiResponseMessages.MaxLimit, nameof(model.Name), 20));
                    if (model.ParentId > 0)
                    {//对菜单栏目深度检查
                        var parentColumn = _businessmodelFactory.PrepareColumnItemModel(model.ParentId);
                        if ((parentColumn.Level + 1) != model.Level)
                            model.Level = parentColumn.Level + 1;
                    }
                    else model.Level = 1;

                    //对栏目语言检查，相同栏目不同语言url添加语言标识
                    var languages = _languageService.GetLanguagesAll();
                    var fromLang = languages.FirstOrDefault(l => l.Id == model.LanguageId);
                    if (model.IsDisplay == EntityEnumConfig.YesorNo.YES && string.IsNullOrEmpty(model.UrlRoute)) //
                    {
                        var breadcrumbs = _businessmodelFactory.GetColumnBreadcrumb(model.Id > 0 ? model.Id : model.ParentId);
                        if(breadcrumbs != null)
                        {
                            //对前端url未设置时，通过系统获取百度翻译或汉字转拼音对url进行转化处理
                            if (breadcrumbs.Any(c => c.Id == model.Id && !c.Name.Equals(model.Name, StringComparison.CurrentCultureIgnoreCase)))
                                breadcrumbs.FirstOrDefault(c => c.Id == model.Id).Name = model.Name;
                        }
                        if(breadcrumbs != null) breadcrumbs = breadcrumbs.Reverse().ToList();
                        if(model.Id == 0) breadcrumbs.Add(model); //新增菜单时无对应数据库记录
                        if(!string.IsNullOrEmpty(_nowaConfig.BaiduFanyiAPPID) && !string.IsNullOrEmpty(_nowaConfig.BaiduFanyiSecretKey))
                        {//是否启用BaiduFanyi
                            var request = new BaiduFanyiRequest();
                            if (languages == null || fromLang == null) request.from = "auto";
                            else request.from = fromLang.LanguageCode;
                            request.to = "en";
                            request.salt = CommonHelper.GenerateRandomDigitCode(10);
                            foreach (var item in breadcrumbs)
                            {
                                if (item.Name.IndexOf(';', StringComparison.InvariantCultureIgnoreCase) >= 0) 
                                    item.Name = item.Name.Replace(";", string.Empty, StringComparison.InvariantCultureIgnoreCase);
                                request.q += item.Name + ";";
                            }
                            var client = EngineContext.Current.Resolve<IHttpClientFactory>().CreateClient(HttpDefineDefaults.DefaultHttpClient);
                            Task<BaiduFanyiResult> GetTransTask = BaiduFanyiSDK.TranslateAsync(client, _nowaConfig, request);
                            GetTransTask.Wait();
                            var baiduTranReuslt = GetTransTask.Result;//await GetIpLocationAsync(loginIp);
                            if (baiduTranReuslt == null) throw new NowaException(ApiResponseMessages.SDKCallError);
                            else
                            {
                                model.UrlRoute += "/" + baiduTranReuslt.trans_result.First().dst.Replace(';', '-').ToLower();
                                model.UrlRoute = Regex.Replace(model.UrlRoute.ToLower(), @"\s+", string.Empty);
                                if(model.UrlRoute.EndsWith('/') || model.UrlRoute.EndsWith('-'))
                                    model.UrlRoute = model.UrlRoute.Remove(model.UrlRoute.Length - 1, 1);
                            }
                        }
                        else //用汉字转拼音方式获取自定义Url
                        {
                            foreach (var item in breadcrumbs)
                            {
                                model.UrlRoute += "-" + CommonHelper.GetSeName(item.Name, true, false);
                            }
                            if(model.UrlRoute.StartsWith('-'))
                                model.UrlRoute = model.UrlRoute.Remove(0, 1).Insert(0, "/");
                        }
                        //对栏目分类添加分类前缀
                        switch (model.ColumnType)
                        {
                            case EntityEnumConfig.ColumnType.NewsColumn:
                                model.UrlRoute = $"/articles{model.UrlRoute}";
                                break;
                            case EntityEnumConfig.ColumnType.BlogColumn:
                                model.UrlRoute = $"/blog{model.UrlRoute}";
                                break;
                            default:
                                break;
                        }
                        model.UrlRoute = model.UrlRoute.AddLanguageSeoCodeToUrl(string.Empty, false, fromLang);
                    } 
                    else if(model.IsDisplay == EntityEnumConfig.YesorNo.YES)
                    {
                        if(!CommonHelper.IsValidURI(model.UrlRoute) && !model.UrlRoute.StartsWith('/'))
                            model.UrlRoute = "/" + model.UrlRoute;
                    }

                    if (!CommonHelper.IsValidURI(model.UrlRoute, UriKind.RelativeOrAbsolute) && model.IsDisplay == EntityEnumConfig.YesorNo.YES)
                        throw new NowaException(ApiResponseMessages.UrlNotCorrect);

                    if (!string.IsNullOrEmpty(model.PageSizeOptions))
                    {
                        var sizeList = model.PageSizeOptions.Split(",").Select(Int32.Parse).ToList();
                        sizeList.Sort((x, y) => x.CompareTo(y));
                        model.PageSizeOptions = string.Join(',', sizeList);
                    }
                    else model.PageSizeOptions = _adminareaSettings.GridPageSizes;
                    if (model.PageSize <= 0) model.PageSize = _adminareaSettings.DefaultGridPageSize;
                    var columnEntity = model.ToEntity<Column>();
                    if (columnEntity.Id == 0) //新增
                    {
                        columnEntity.CreatedOnTimeUtc = columnEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                        _columnService.InsertColumn(columnEntity);
                        //DavidLee 2020/07/31 增加基于栏目菜单模块的权限管理分配(文章管理/博客管理)
                        //只针对新增栏目设置
                        InsertRoleColumnAuthorize(columnEntity);
                    }
                    else
                    {
                        columnEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                        _columnService.UpdateColumn(columnEntity);
                    }
                    return SuccessJson(ApiResponseMessages.ColumnUpdateSeccess);
                }
                catch (Exception ex)
                {
                    return ErrorJson(ex.Message);
                }
            }
            return ErrorJson(ApiResponseMessages.ModelBindingError);
        }
        //DavidLee 2020/07/31 增加基于栏目菜单模块的权限管理分配(文章管理/博客管理) 
        private void InsertRoleColumnAuthorize(Column column)
        {
            if (column == null) return;
            IList<SystemModuleModel> ColumnReferenceModules = null;
            var systemmanageFactory = EngineContext.Current.Resolve<ISystemManageModelFactory>();
            //与栏目菜单相关联的模块： 文章管理/博客管理
            //* 注：
            //  偷懒 在此固定获取 文章管理及博客管理 模块的数据库Id,如果Id发生变化，请在此处理
            if (column.ColumnType == EntityEnumConfig.ColumnType.NewsColumn)
            {
                var newsSettings = EngineContext.Current.Resolve<NewsSettings>();
                if (newsSettings.ColumnAuthorize)
                    ColumnReferenceModules = systemmanageFactory.GetSystemModuleModelsById(4); //文章管理
            }
            else if (column.ColumnType == EntityEnumConfig.ColumnType.BlogColumn)
            {
                var blogSettings = EngineContext.Current.Resolve<BlogSettings>();
                if (blogSettings.ColumnAuthorize)
                    ColumnReferenceModules = systemmanageFactory.GetSystemModuleModelsById(19); //博客管理
            }

            if (ColumnReferenceModules == null) return;
            else if (ColumnReferenceModules.Count == 0) return;
            var adminuserService = EngineContext.Current.Resolve<IAdminUserService>();
            var roleModels = adminuserService.GetAdminRoleModelsAll();
            if (roleModels == null) return;
            var roleMappings = new List<AdminRoleBusColumnMapping>();
            foreach (var role in roleModels)
            {//当栏目-角色权限开启时，为新增栏目分配每个角色的权限控制，默认都有操作权限
                var assignedBtns = ColumnReferenceModules.First().ModuleAssignedButtons;
                var mapping = new AdminRoleBusColumnMapping
                {
                    FKAdminRoleId = role.Id,
                    FKColumnId = column.Id,
                    AssignedButtonIds = assignedBtns == null ? string.Empty : string.Join(",", assignedBtns),
                    IsAllow = EntityEnumConfig.YesorNo.YES,
                };
                mapping.AuthorizedButtonIds = mapping.AssignedButtonIds;
                roleMappings.Add(mapping);
            }
            if(roleMappings.Count > 0) _columnService.InsertAdminRoleColumnAuthorize(roleMappings);
        }

        [HttpDelete(BackendApiRouteConfig.BackendDeleteColumn)]
        public async Task<IActionResult> BackendDeleteColumn([FromBody]DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                if (_businessmodelFactory.ColumnHasChild(node.EntityId))
                    throw new NowaException(ApiResponseMessages.DeleteNodeHasChildNodes);
                var deleteNode = _columnService.GetColumnById(node.EntityId);
                if (deleteNode == null || deleteNode.IsActive == EntityEnumConfig.YesorNo.No)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);
                
                deleteNode.SysLogLvl = SystemLogLevel.Information;
                deleteNode.SysLogMsg = string.Format("菜单Id：{0}被删除，操作人：{1}", deleteNode.Id, _workContext.CurrentAdminUser.UserName);
                _columnService.DeleteColumn(deleteNode);
                return SuccessJson(ApiResponseMessages.UpdateSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpPost(BackendApiRouteConfig.BackendColumnImageUpload)]
        public async Task<IActionResult> BackendColumnImageUpload([FromForm]ImageUploadForm imagedata)
        {
            try
            {
                if (imagedata == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (imagedata.ImageForm == null) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var columnItem = _columnService.GetColumnById(imagedata.Id);
                FileUpload picture = null;
                var retunData = string.Empty;
                if(columnItem == null || string.IsNullOrEmpty(imagedata.ImageUrl))
                {//在栏目菜单未创建前添加图片 直接新加图片并返回图片地址
                 //或已存在栏目下未添加过图片 new insert image
                    picture = _fileuploadService.InsertFileEntity(imagedata.ImageForm, nameof(UploadUseCategory.ColumnImage));
                    retunData = picture.Id.ToString() + ";";
                    retunData += _fileuploadService.GetFileUrl(picture);
                    return SuccessJson(ApiResponseMessages.ColumnImageUploadSuccess, retunData);
                }
                else
                {//update image
                    //上传的imageUrl为column表存储图片对应字段： IconImageUrl, CoverImageUrl
                    //imageUrl 格式为'FileUploadId;ImageUrl' 如"1;/uploaded/Image/20200211/logo.png"
                    //保存FileUpload存储的图片Id 和 图片存储路径
                    //图片Id用于删除原有图片数据
                    //Url用于前端快速显示图片 而不用通过图片id再去查图片路径
                    //只有更改图片时才删除原有图片
                    var oldImageData = imagedata.ImageUrl.Split(';').ToArray();
                    if (oldImageData.Length != 2) throw new NowaException(string.Format(ApiResponseMessages.BugReport, "ImageUrl Not Correct"));
                    picture = _fileuploadService.GetFileUploadEntityById(int.Parse(oldImageData[0]));
                    if(picture == null)
                    {
                        picture = _fileuploadService.InsertFileEntity(imagedata.ImageForm, nameof(UploadUseCategory.ColumnImage));
                        retunData = picture.Id.ToString() + ";";
                        retunData += _fileuploadService.GetFileUrl(picture);
                        return SuccessJson(ApiResponseMessages.ColumnImageUploadSuccess, retunData);
                    }
                    else
                    {
                        oldImageData[1] = picture.SeoFilename;
                        var fileProvider = EngineContext.Current.Resolve<INowaFileProvider>();
                        picture.FileBinary = new FileBinary
                        {
                            FKFileUploadId = picture.Id,
                            BinaryData = GetFileBits(imagedata.ImageForm)
                        };
                        picture.SeoFilename = _fileuploadService.GetFileSeName(fileProvider.GetFileNameWithoutExtension(imagedata.ImageForm.FileName));
                        picture.FileType = FileType.Image;
                        picture.StoreType = EntityEnumConfig.FileStoreType.LocalStorage;
                        picture.TitleAttribute = "";
                        picture.AltAttribute = "";
                        picture.IsNew = EntityEnumConfig.YesorNo.YES;
                        picture.MimeType = imagedata.ImageForm.ContentType;
                        picture.Category = nameof(UploadUseCategory.ColumnImage);
                        picture.UpdatedOnTimeUtc = DateTime.UtcNow;
                        if (string.IsNullOrEmpty(picture.MimeType)) 
                            picture.MimeType = MimeTypes.GetSupportFileMimetypeByFileExt(fileProvider.GetFileExtension(imagedata.ImageForm.FileName));
                        
                        picture = _fileuploadService.UpdateFileEntityWithBinary(picture, oldImageData[1]);
                        retunData = picture.Id.ToString() + ";";
                        retunData += _fileuploadService.GetFileUrl(picture);
                        return SuccessJson(ApiResponseMessages.ColumnImageUploadSuccess, retunData);
                    }
                }
            }
            catch(Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [HttpGet(BackendApiRouteConfig.BackendColumnSetOrder)]
        public async Task<IActionResult> BackendColumnSetOrder(int columnid, int order = 0)
        {
            try
            {
                if (order <= 0) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var columnEntity = _columnService.GetColumnById(columnid);
                if (columnEntity == null) throw new NowaException(ApiResponseMessages.EntityNotFound);
                columnEntity.DisplayOrder = order;
                columnEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                _columnService.UpdateColumn(columnEntity);
                return SuccessJson(ApiResponseMessages.DisplayOrderSetSuccess, columnEntity.DisplayOrder);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region NewsManage Api
        /// <summary>
        /// DavidLee 2020/07/31 增加按用户角色权限查询筛选数据功能
        /// 为兼容其他功能调用API，需要增加参数 isauth并设置默认值
        /// </summary>
        /// <param name="cid"></param>
        /// 
        /// <param name="page"></param>
        /// <param name="pagesize"></param>
        /// <returns></returns>
        [Route(BackendApiRouteConfig.BackendLoadNewsList)]
        public async Task<IActionResult> BackendLoadNewsList(int cid = 0, bool isauth = false, int page = 1, int pagesize = 20)
        {
            try
            {
                var searchModel = new NewsItemSearchModel
                {
                    ColumnId = cid,
                    Page = page,
                    PageSize = pagesize
                };
                if (isauth && _newsSettings.Enabled && _newsSettings.ColumnAuthorize)
                {
                    if (_workContext.IsAdmin) searchModel.RoleIds = null;
                    else
                    {
                        var CurrentUser = _workContext.CurrentAdminUser;
                        searchModel.RoleIds = CurrentUser.GetAdminRoles().Select(r => r.Id).ToArray();
                    }
                }
                var newslist = _businessmodelFactory.PrepareNewsItemListModel(searchModel);
                return SuccessJson("", newslist);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        //后台文章管理搜索检索功能
        [Route(BackendApiRouteConfig.BackenNewsSearch)]
        public async Task<IActionResult> BackenNewsSearch(string s, int page = 1, int pagesize = 20)
        {
            try
            {
                if (string.IsNullOrEmpty(s)) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                if (_cachedsearchEngine == null)
                    _cachedsearchEngine = EngineContext.Current.Resolve<ISearchEngine<AppDbObjectContext>>();
                var searchResult = _cachedsearchEngine.ScoredSearch<NewsItem>(new SearchOptions(s, page, pagesize, typeof(NewsItem)));
                var simpleHtmlFormatter = new SimpleHTMLFormatter("<span style='color:red;font-size: 1.1em;font-weight:700;'>", "</span>");
                //Create a highlighter, enter htmlformatter and Pangu participle object semgent
                var highlighter = new Highlighter(simpleHtmlFormatter, new Segment()) { FragmentSize = 200 };
                //Directory Directory = new RAMDirectory();
                //Analyzer analyzer = new StandardAnalyzer(Lucene.Net.Util.LuceneVersion.LUCENE_48);
                ILuceneIndexSearcher searcher = _cachedsearchEngine.LuceneIndexSearcher; //new LuceneIndexSearcher(Directory, analyzer, new MemoryCache(new MemoryCacheOptions()));
                var keywords = searcher.CutKeywords(s);
                var datetimeHelper = EngineContext.Current.Resolve<IDateTimeHelper>();
                var columns = _columnService.GetColumnList();
                // 高亮截取处理
                var results = searchResult.Results.Select(result =>
                {
                    var searchentity = result.Entity;
                    string frag;
                    foreach (var word in keywords)
                    {
                        if (searchentity.Title.Contains(word) && !string.IsNullOrEmpty(frag = highlighter.GetBestFragment(word, searchentity.Title)))
                        {
                            searchentity.Title = frag;
                            break;
                        }
                    }
                    bool handled = false;
                    searchentity.Contents = searchentity.Contents.RemoveHtmlTag();
                    foreach (var word in keywords)
                    {
                        if (searchentity.Contents.Contains(word) && !string.IsNullOrEmpty(frag = highlighter.GetBestFragment(word, searchentity.Contents)))
                        {
                            searchentity.Contents = frag;
                            handled = true;
                            break;
                        }
                    }

                    if (searchentity.Contents.Length > 200 && !handled)
                    {
                        searchentity.Contents = searchentity.Contents.Substring(0, 200);
                        searchentity.Contents += "...";
                    }
                    searchentity.CreatedOnTimeUtc = datetimeHelper.ConvertToUserTime(searchentity.CreatedOnTimeUtc, DateTimeKind.Local);
                    //借用MetaTitle字段存储文章所属栏目名称
                    searchentity.MetaTitle = columns.FirstOrDefault(c => c.Id == searchentity.FKColumnId).Name;
                    return searchentity;
                }).ToList();
                //记录搜索关键字
                var news = new NewsItem();
                news.LogSearchNewsEvent(s);

                return SuccessJson("", new
                {
                    Results = results,
                    Elapsed = searchResult.Elapsed,
                    Total = searchResult.TotalHits
                });
            }
            catch (Exception ex)
            {
                var logService = EngineContext.Current.Resolve<ISystemLogService>();
                logService.Error(ex.Message, ex);
                return ErrorJson(ex.Message);
            }
        }

        internal class UploadResponse
        {
            public int FileUploadId { get; set; }
            public string FileUrl { get; set; }
            public string FileTitle { get; set; }
        }

        /// <summary>
        /// 通用文件上传功能
        /// </summary>
        /// <param name="formdata"></param>
        /// <returns></returns>
        [HttpPost(BackendApiRouteConfig.BackendNewsFileUpload)]
        public async Task<IActionResult> BackendNewsFileUpload([FromForm] FileUploadForm formdata)
        {
            try
            {
                if (formdata == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (formdata.FormData == null) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                EntityEnumConfig.FileStoreType storeType = formdata.CloudUpload
                                                         ? EntityEnumConfig.FileStoreType.QiniuCloud
                                                         : EntityEnumConfig.FileStoreType.LocalStorage;
                if (storeType == EntityEnumConfig.FileStoreType.QiniuCloud)
                {
                    if (!_nowaConfig.QiniuCloudStorageEnabled)
                        throw new NowaException(ApiResponseMessages.CloudUploadNotSupport);
                }
                if (storeType == EntityEnumConfig.FileStoreType.LocalStorage && formdata.FormData.Length > _mediaSettings.FileMaximumSizeBytes)
                    throw new NowaException(ApiResponseMessages.RecommendCloudUpload);
                var fileProvider = CommonHelper.DefaultFileProvider;
                var fileExtension = fileProvider.GetFileExtension(formdata.FormData.FileName);
                if (!MimeTypes.IsSupportByFileExt(fileExtension))
                    throw new NowaException(ApiResponseMessages.FileUploadNotSupport);
                //DavidLee 2020/08/07 更改文件上传功能为通用，不再限定为文章图片上传
                //var newsItem = _newsService.GetNewsItemById(formdata.EntityId);
                FileUpload file = null;
                var retunData = new UploadResponse
                {
                    FileUploadId = 0,
                    FileUrl = "",
                    FileTitle = ""
                };
                if (formdata.EntityId == 0 || formdata.FileUploadId == 0)
                {//在文章未创建前添加图片 直接新加图片并返回图片地址
                 //或已存在文章下未添加过图片 new insert image
                    file = _fileuploadService.InsertFileEntity(formdata.FormData, formdata.UseCase);
                    retunData.FileUploadId = file.Id;
                    retunData.FileUrl = _fileuploadService.GetFileUrl(file);
                    retunData.FileTitle = file.TitleAttribute;
                    return SuccessJson(ApiResponseMessages.FileUploadSuccess, retunData);
                }
                else
                {//update image
                    file = _fileuploadService.GetFileUploadEntityById(formdata.FileUploadId);
                    if (file == null)
                    {
                        file = _fileuploadService.InsertFileEntity(formdata.FormData, formdata.UseCase);
                        retunData.FileUploadId = file.Id;
                        retunData.FileUrl = _fileuploadService.GetFileUrl(file);
                        retunData.FileTitle = file.TitleAttribute;
                        return SuccessJson(ApiResponseMessages.FileUploadSuccess, retunData);
                    }
                    else
                    {
                        file.FileBinary = new FileBinary
                        {
                            FKFileUploadId = file.Id,
                            BinaryData = GetFileBits(formdata.FormData)
                        };
                        file.SeoFilename = _fileuploadService.GetFileSeName(fileProvider.GetFileNameWithoutExtension(formdata.FormData.FileName));
                        file.StoreType = EntityEnumConfig.FileStoreType.LocalStorage;
                        file.TitleAttribute = "";
                        file.AltAttribute = "";
                        file.IsNew = EntityEnumConfig.YesorNo.YES;
                        file.MimeType = formdata.FormData.ContentType;
                        file.Category = formdata.UseCase;
                        file.UpdatedOnTimeUtc = DateTime.UtcNow;
                        if (string.IsNullOrEmpty(file.MimeType))
                            file.MimeType = MimeTypes.GetSupportFileMimetypeByFileExt(fileProvider.GetFileExtension(formdata.FormData.FileName));

                        file = _fileuploadService.UpdateFileEntityWithBinary(file, file.SeoFilename);
                        retunData.FileUploadId = file.Id;
                        retunData.FileUrl = _fileuploadService.GetFileUrl(file);
                        retunData.FileTitle = file.TitleAttribute;
                        return SuccessJson(ApiResponseMessages.FileUploadSuccess, retunData);
                    }
                }
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        internal class DeleteFileResponse
        {
            public string NewFileIds { get; set; }
            public string NewFileUrls { get; set; }
        }
        /// <summary>
        /// 删除文章图片相册
        /// </summary>
        /// <param name="imageids">fileupload ids to be deleted</param>
        /// <param name="imageurls">fileupload urls to be deleted</param>
        /// <returns></returns>
        [HttpPost(BackendApiRouteConfig.BackendNewsDeleteFileList)]
        public async Task<IActionResult> BackendNewsDeleteFileList([FromBody] DeleteFileInfo deleteinfo)
        {
            try
            {
                if (string.IsNullOrEmpty(deleteinfo.FileIds) || string.IsNullOrEmpty(deleteinfo.FileUrls))
                    throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                IList<int> delIds = deleteinfo.FileIds.Split(',').Select(Int32.Parse).ToList();
                IList<string> delUrls = deleteinfo.FileUrls.Split(',').ToList();
                if (delIds.Count != delUrls.Count)
                    throw new NowaException(string.Format(ApiResponseMessages.BugReport, "Id length not equals to url length."));

                var deleteFiles = _fileuploadService.GetFileUploadList(delIds.ToArray());
                //删除服务器文件及数据库上传文件记录
                foreach (var file in deleteFiles)
                {
                    _fileuploadService.DeleteFileUploadEntity(file);
                }
                DeleteFileResponse returnData = new DeleteFileResponse
                {
                    NewFileIds = string.Empty,
                    NewFileUrls = string.Empty
                };
                IList<GenericAttribute> newsItemExtraInfo = _gaService.GetAttributesForEntity(deleteinfo.NewsItemId, nameof(NewsItem));
                if (newsItemExtraInfo != null)
                {
                    List<int> newIds = null;
                    List<string> newUrls = null;
                    foreach (var attribute in newsItemExtraInfo)
                    {
                        if (deleteinfo.IdPropName == attribute.Key)
                        {
                            newIds = attribute.Value.Split(',').Select(Int32.Parse).ToList();
                            newIds = newIds.Except(delIds).ToList();
                        }
                        if (deleteinfo.UrlPropName == attribute.Key)
                        {
                            newUrls = attribute.Value.Split(',').ToList();
                            newUrls = newUrls.Except(delUrls).ToList();
                        }
                    }
                    var newsItem = _newsService.GetNewsItemById(deleteinfo.NewsItemId);
                    if (newIds != null)
                    {
                        if (newIds.Count > 0)
                        {
                            returnData.NewFileIds = string.Join(',', newIds);
                            //returnData.NewFileUrls = string.Join(',', newUrls);
                        }
                    }

                    if (newsItem != null)
                        _gaService.SaveAttribute(newsItem, deleteinfo.IdPropName, returnData.NewFileIds);
                    //_gaService.SaveAttribute(newsItem, deleteinfo.UrlPropName, returnData.NewFileUrls);
                }
                return SuccessJson(ApiResponseMessages.FileDeleteSuccess, returnData);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 删除文章封面图片
        /// </summary>
        /// <param name="newsid"></param>
        /// <param name="imageid"></param>
        /// <returns></returns>
        [HttpGet(BackendApiRouteConfig.BackendNewsDeleteCoverImage)]
        public async Task<IActionResult> BackendNewsDeleteCoverImage(int newsid, int imageid)
        {
            try
            {
                if (imageid <= 0)
                    throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var deleteImageFile = _fileuploadService.GetFileUploadEntityById(imageid);
                //删除服务器文件及数据库上传文件记录
                _fileuploadService.DeleteFileUploadEntity(deleteImageFile);
                string defaultImage = "0;" + _fileuploadService.GetDefaultFileUrl();
                if (newsid > 0)
                {
                    var newsItem = _newsService.GetNewsItemById(newsid);
                    if (newsItem != null)
                    {
                        newsItem.CoverImageUrl = defaultImage;
                        _newsService.UpdateNews(newsItem);
                    }
                }
                return SuccessJson(ApiResponseMessages.FileDeleteSuccess, defaultImage);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [Route(BackendApiRouteConfig.BackendNewsSetRecommend)]
        public async Task<IActionResult> BackendNewsSetRecommend(int newsid)
        {
            try
            {
                var newsEntity = _newsService.GetNewsItemById(newsid);
                if (newsEntity == null) throw new NowaException(ApiResponseMessages.EntityNotFound);
                newsEntity.IsRecommend = newsEntity.IsRecommend == EntityEnumConfig.YesorNo.YES
                                       ? EntityEnumConfig.YesorNo.No
                                       : EntityEnumConfig.YesorNo.YES;
                newsEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                _newsService.UpdateNews(newsEntity);
                return SuccessJson("", newsEntity.IsRecommend == EntityEnumConfig.YesorNo.YES ? true : false);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [Route(BackendApiRouteConfig.BackendNewsSetOrder)]
        public async Task<IActionResult> BackendNewsSetOrder(int newsid, int order = 0)
        {
            try
            {
                if (order <= 0) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var newsEntity = _newsService.GetNewsItemById(newsid);
                if (newsEntity == null) throw new NowaException(ApiResponseMessages.EntityNotFound);
                newsEntity.DisplayOrder = order;
                newsEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                _newsService.UpdateNews(newsEntity);
                return SuccessJson(ApiResponseMessages.DisplayOrderSetSuccess, newsEntity.DisplayOrder);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        //DavidLee 2020/08/03 增加栏目权限控制
        [HttpGet(BackendApiRouteConfig.BackendCheckColumnAuthorize)]
        public virtual IActionResult BackendCheckColumnAuthorize(int columnid, int buttonid)
        {
            bool isAuthorized = CheckColumnAuthorize(columnid, buttonid);
            return SuccessJson(!isAuthorized ? ApiResponseMessages.ColumnButtonNotAuthorize : "", isAuthorized);
        }

        private bool CheckColumnAuthorize(int columnid, int buttonid)
        {
            if (_newsSettings.Enabled && _newsSettings.ColumnAuthorize)
            {//编辑新闻检查用户栏目权限
             //Edit or Copy or Add
                if (!_permissionService.AuthorizeColumnButton(columnid, buttonid))
                    return false;
            }
            return true;
        }

        [HttpPost(BackendApiRouteConfig.BackendNewsEdit)]
        public async Task<IActionResult> BackendNewsEdit([FromBody] NewsItemModel newsitemModel)
        {
            try
            {
                if (newsitemModel == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (newsitemModel.FKColumnId <= 0
                 || string.IsNullOrEmpty(newsitemModel.Title))
                    throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);

                if (string.IsNullOrEmpty(newsitemModel.Publisher))
                    newsitemModel.Publisher = _workContext.CurrentAdminUser.UserName;

                var newsEntity = newsitemModel.ToEntity<NewsItem>();
                newsEntity.CreatedOnTimeUtc = _datetimeHelper.ConvertToUtcTime(newsitemModel.CreatedOnTime);
                newsEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                newsEntity.StartTaskTimeUtc = null;
                newsEntity.IsActive = EntityEnumConfig.YesorNo.YES;
                if (newsEntity.Id > 0) //Edit
                {
                    _newsService.UpdateNews(newsEntity);
                }
                else //Create
                {
                    _newsService.InsertNews(newsEntity);
                }

                if (!string.IsNullOrEmpty(newsitemModel.ImageIds))
                    _gaService.SaveAttribute(newsEntity, nameof(newsitemModel.ImageIds), newsitemModel.ImageIds);
                //_gaService.SaveAttribute(newsEntity, nameof(newsitemModel.ImageUrls), newsitemModel.ImageUrls);
                if (!string.IsNullOrEmpty(newsitemModel.VideoIds))
                    _gaService.SaveAttribute(newsEntity, nameof(newsitemModel.VideoIds), newsitemModel.VideoIds);
                //_gaService.SaveAttribute(newsEntity, nameof(newsitemModel.VideoUrls), newsitemModel.VideoUrls);
                if (!string.IsNullOrEmpty(newsitemModel.FileIds))
                    _gaService.SaveAttribute(newsEntity, nameof(newsitemModel.FileIds), newsitemModel.FileIds);
                return SuccessJson(ApiResponseMessages.NewsUpdateSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpDelete(BackendApiRouteConfig.BackendNewsDelete)]
        public async Task<IActionResult> BackendNewsDelete([FromBody] DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                var deleteNode = _newsService.GetNewsItemById(node.EntityId);
                if (deleteNode == null)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);

                //DavidLee 2020/08/03 增加栏目权限控制
                if (!CheckColumnAuthorize(deleteNode.FKColumnId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);

                _newsService.DeleteNewsBatch(new List<NewsItem> { deleteNode });
                return SuccessJson(string.Format(ApiResponseMessages.NewsDeleteCount, 1));
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region BlogManage Api
        [Route(BackendApiRouteConfig.BackendLoadBlogList)]
        public async Task<IActionResult> BackendLoadBlogList(int cid = 0, bool isauth = false, int page = 1, int pagesize = 20)
        {
            try
            {
                var searchModel = new BlogItemSearchModel
                {
                    ColumnId = cid,
                    Page = page,
                    PageSize = pagesize
                };
                if (isauth && _blogSettings.Enabled && _blogSettings.ColumnAuthorize)
                {
                    var CurrentUser = _workContext.CurrentAdminUser;
                    searchModel.RoleIds = CurrentUser.GetAdminRoles().Select(r => r.Id).ToArray();
                }
                var bloglist = _businessmodelFactory.PrepareBlogItemListModel(searchModel);
                return SuccessJson("", bloglist);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        //后台博客文章管理搜索检索功能
        [Route(BackendApiRouteConfig.BackenBlogSearch)]
        public async Task<IActionResult> BackenBlogSearch(string s, int page = 1, int pagesize = 20)
        {
            try
            {
                if (string.IsNullOrEmpty(s)) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                if (_cachedsearchEngine == null)
                    _cachedsearchEngine = EngineContext.Current.Resolve<ISearchEngine<AppDbObjectContext>>();
                var searchResult = _cachedsearchEngine.ScoredSearch<BlogItem>(new SearchOptions(s, page, pagesize, typeof(BlogItem)));
                var simpleHtmlFormatter = new SimpleHTMLFormatter("<span style='color:red;font-size: 1.1em;font-weight:700;'>", "</span>");
                //Create a highlighter, enter htmlformatter and Pangu participle object semgent
                var highlighter = new Highlighter(simpleHtmlFormatter, new Segment()) { FragmentSize = 200 };
                ILuceneIndexSearcher searcher = _cachedsearchEngine.LuceneIndexSearcher; //new LuceneIndexSearcher(Directory, analyzer, new MemoryCache(new MemoryCacheOptions()));
                var keywords = searcher.CutKeywords(s);
                var datetimeHelper = EngineContext.Current.Resolve<IDateTimeHelper>();
                var columns = _columnService.GetColumnList();
                // 高亮截取处理
                var results = searchResult.Results.Select(result =>
                {
                    var searchentity = result.Entity;
                    string frag;
                    foreach (var word in keywords)
                    {
                        if (searchentity.Title.Contains(word) && !string.IsNullOrEmpty(frag = highlighter.GetBestFragment(word, searchentity.Title)))
                        {
                            searchentity.Title = frag;
                            break;
                        }
                    }
                    bool handled = false;
                    searchentity.Contents = searchentity.Contents.RemoveHtmlTag();
                    foreach (var word in keywords)
                    {
                        if (searchentity.Contents.Contains(word) && !string.IsNullOrEmpty(frag = highlighter.GetBestFragment(word, searchentity.Contents)))
                        {
                            searchentity.Contents = frag;
                            handled = true;
                            break;
                        }
                    }

                    if (searchentity.Contents.Length > 200 && !handled)
                    {
                        searchentity.Contents = searchentity.Contents.Substring(0, 200);
                        searchentity.Contents += "...";
                    }
                    searchentity.CreatedOnTimeUtc = datetimeHelper.ConvertToUserTime(searchentity.CreatedOnTimeUtc, DateTimeKind.Local);
                    //借用MetaTitle字段存储文章所属栏目名称
                    searchentity.MetaTitle = columns.FirstOrDefault(c => c.Id == searchentity.FKColumnId).Name;
                    return searchentity;
                }).ToList();
                //记录搜索关键字
                var blog = new BlogItem();
                blog.LogSearchBlogEvent(s);

                return SuccessJson("", new
                {
                    Results = results,
                    Elapsed = searchResult.Elapsed,
                    Total = searchResult.TotalHits
                });
            }
            catch (Exception ex)
            {
                var logService = EngineContext.Current.Resolve<ISystemLogService>();
                logService.Error(ex.Message, ex);
                return ErrorJson(ex.Message);
            }
        }

        [HttpPost(BackendApiRouteConfig.BackendBlogFileUpload)]
        public async Task<IActionResult> BackendBlogFileUpload([FromForm]FileUploadForm formdata)
        {
            try
            {
                if (formdata == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (formdata.FormData == null) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                EntityEnumConfig.FileStoreType storeType = formdata.CloudUpload
                                                         ? EntityEnumConfig.FileStoreType.QiniuCloud
                                                         : EntityEnumConfig.FileStoreType.LocalStorage;
                if (storeType == EntityEnumConfig.FileStoreType.QiniuCloud)
                {
                    if (!_nowaConfig.QiniuCloudStorageEnabled)
                        throw new NowaException(ApiResponseMessages.CloudUploadNotSupport);
                }
                if (storeType == EntityEnumConfig.FileStoreType.LocalStorage && formdata.FormData.Length > _mediaSettings.FileMaximumSizeBytes)
                    throw new NowaException(ApiResponseMessages.RecommendCloudUpload);
                var fileProvider = CommonHelper.DefaultFileProvider;
                var fileExtension = fileProvider.GetFileExtension(formdata.FormData.FileName);
                if (!MimeTypes.IsSupportByFileExt(fileExtension))
                    throw new NowaException(ApiResponseMessages.FileUploadNotSupport);

                var blogItem = _blogService.GetBlogItemById(formdata.EntityId);
                FileUpload file = null;
                var retunData = new UploadResponse
                {
                    FileUploadId = 0,
                    FileUrl = ""
                };
                if (blogItem == null || formdata.FileUploadId == 0)
                {//在文章未创建前添加图片 直接新加图片并返回图片地址
                 //或已存在文章下未添加过图片 new insert image
                    file = _fileuploadService.InsertFileEntity(formdata.FormData, formdata.UseCase);
                    retunData.FileUploadId = file.Id;
                    retunData.FileUrl = _fileuploadService.GetFileUrl(file);
                    return SuccessJson(ApiResponseMessages.FileUploadSuccess, retunData);
                }
                else
                {//update image
                    file = _fileuploadService.GetFileUploadEntityById(formdata.FileUploadId);
                    if (file == null)
                    {
                        file = _fileuploadService.InsertFileEntity(formdata.FormData, formdata.UseCase);
                        retunData.FileUploadId = file.Id;
                        retunData.FileUrl = _fileuploadService.GetFileUrl(file);
                        return SuccessJson(ApiResponseMessages.FileUploadSuccess, retunData);
                    }
                    else
                    {
                        file.FileBinary = new FileBinary
                        {
                            FKFileUploadId = file.Id,
                            BinaryData = GetFileBits(formdata.FormData)
                        };
                        file.SeoFilename = _fileuploadService.GetFileSeName(fileProvider.GetFileNameWithoutExtension(formdata.FormData.FileName));
                        file.StoreType = EntityEnumConfig.FileStoreType.LocalStorage;
                        file.TitleAttribute = "";
                        file.AltAttribute = "";
                        file.IsNew = EntityEnumConfig.YesorNo.YES;
                        file.MimeType = formdata.FormData.ContentType;
                        file.Category = formdata.UseCase;
                        file.UpdatedOnTimeUtc = DateTime.UtcNow;
                        if (string.IsNullOrEmpty(file.MimeType))
                            file.MimeType = MimeTypes.GetSupportFileMimetypeByFileExt(fileProvider.GetFileExtension(formdata.FormData.FileName));

                        file = _fileuploadService.UpdateFileEntityWithBinary(file, file.SeoFilename);
                        retunData.FileUploadId = file.Id;
                        retunData.FileUrl = _fileuploadService.GetFileUrl(file);
                        return SuccessJson(ApiResponseMessages.FileUploadSuccess, retunData);
                    }
                }
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 删除博客文章图片相册
        /// </summary>
        /// <param name="imageids">fileupload ids to be deleted</param>
        /// <param name="imageurls">fileupload urls to be deleted</param>
        /// <returns></returns>
        [HttpPost(BackendApiRouteConfig.BackendBlogDeleteFileList)]
        public async Task<IActionResult> BackendBlogDeleteFileList([FromBody]DeleteFileInfo deleteinfo)
        {
            try
            {
                if (string.IsNullOrEmpty(deleteinfo.FileIds) || string.IsNullOrEmpty(deleteinfo.FileUrls))
                    throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                IList<int> delIds = deleteinfo.FileIds.Split(',').Select(Int32.Parse).ToList();
                IList<string> delUrls = deleteinfo.FileUrls.Split(',').ToList();
                if (delIds.Count != delUrls.Count)
                    throw new NowaException(string.Format(ApiResponseMessages.BugReport, "Id length not equals to url length."));

                var deleteFiles = _fileuploadService.GetFileUploadList(delIds.ToArray());
                //删除服务器文件及数据库上传文件记录
                foreach (var file in deleteFiles)
                {
                    _fileuploadService.DeleteFileUploadEntity(file);
                }
                DeleteFileResponse returnData = new DeleteFileResponse
                {
                    NewFileIds = string.Empty,
                    NewFileUrls = string.Empty
                };
                IList<GenericAttribute> blogItemExtraInfo = _gaService.GetAttributesForEntity(deleteinfo.NewsItemId, nameof(BlogItem));
                if (blogItemExtraInfo != null)
                {
                    List<int> blogIds = null;
                    List<string> newUrls = null;
                    foreach (var attribute in blogItemExtraInfo)
                    {
                        if (deleteinfo.IdPropName == attribute.Key)
                        {
                            blogIds = attribute.Value.Split(',').Select(Int32.Parse).ToList();
                            blogIds = blogIds.Except(delIds).ToList();
                        }
                        if (deleteinfo.UrlPropName == attribute.Key)
                        {
                            newUrls = attribute.Value.Split(',').ToList();
                            newUrls = newUrls.Except(delUrls).ToList();
                        }
                    }
                    var blogItem = _blogService.GetBlogItemById(deleteinfo.NewsItemId);
                    if(blogIds != null)
                    {
                        if (blogIds.Count > 0)
                        {
                            returnData.NewFileIds = string.Join(',', blogIds);
                            //returnData.NewFileUrls = string.Join(',', newUrls);
                        }
                    }
                    if (blogItem != null)
                        _gaService.SaveAttribute(blogItem, deleteinfo.IdPropName, returnData.NewFileIds);
                    //_gaService.SaveAttribute(blogItem, deleteinfo.UrlPropName, returnData.NewFileUrls);
                }
                return SuccessJson(ApiResponseMessages.FileDeleteSuccess, returnData);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [Route(BackendApiRouteConfig.BackendBlogSetRecommend)]
        public async Task<IActionResult> BackendBlogSetRecommend(int blogid)
        {
            try
            {
                var blogEntity = _blogService.GetBlogItemById(blogid);
                if (blogEntity == null) throw new NowaException(ApiResponseMessages.EntityNotFound);
                blogEntity.IsRecommend = blogEntity.IsRecommend == EntityEnumConfig.YesorNo.YES
                                       ? EntityEnumConfig.YesorNo.No
                                       : EntityEnumConfig.YesorNo.YES;
                blogEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                _blogService.UpdateBlog(blogEntity);
                return SuccessJson("", blogEntity.IsRecommend == EntityEnumConfig.YesorNo.YES ? true : false);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [HttpPost(BackendApiRouteConfig.BackendBlogEdit)]
        public async Task<IActionResult> BackendBlogEdit([FromBody]BlogItemModel blogitemModel)
        {
            try
            {
                //JsonSerializer serializer = new JsonSerializer();
                //BlogItemModel blogModel = (BlogItemModel)serializer.Deserialize(new JTokenReader(blogitemModel), typeof(BlogItemModel));
                //return SuccessJson("", blogitemModel);
                if (blogitemModel == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (blogitemModel.FKColumnId <= 0
                 || string.IsNullOrEmpty(blogitemModel.Title))
                    throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);

                if (string.IsNullOrEmpty(blogitemModel.Publisher))
                    blogitemModel.Publisher = _workContext.CurrentAdminUser.UserName;

                var blogEntity = blogitemModel.ToEntity<BlogItem>();
                blogEntity.CreatedOnTimeUtc = blogEntity.UpdatedOnTimeUtc = DateTime.UtcNow;
                blogEntity.StartTaskTimeUtc = null;
                blogEntity.IsActive = EntityEnumConfig.YesorNo.YES;
                if (blogEntity.Id > 0) //Edit
                {
                    _blogService.UpdateBlog(blogEntity);
                }
                else //Create
                {
                    _blogService.InsertBlog(blogEntity);
                }

                if (!string.IsNullOrEmpty(blogitemModel.ImageIds))
                    _gaService.SaveAttribute(blogEntity, nameof(blogitemModel.ImageIds), blogitemModel.ImageIds);
                if (!string.IsNullOrEmpty(blogitemModel.VideoIds))
                    _gaService.SaveAttribute(blogEntity, nameof(blogitemModel.VideoIds), blogitemModel.VideoIds);
                return SuccessJson(ApiResponseMessages.BlogUpdateSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpDelete(BackendApiRouteConfig.BackendBlogDelete)]
        public async Task<IActionResult> BackendBlogDelete([FromBody]DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                var deleteNode = _blogService.GetBlogItemById(node.EntityId);
                if (deleteNode == null)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);

                _blogService.DeleteBlogsBatch(new List<BlogItem> { deleteNode });
                return SuccessJson(string.Format(ApiResponseMessages.BlogDeleteCount, 1));
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region ResourceManage
        [HttpPost(BackendApiRouteConfig.BackendLoadResourceList)]
        public async Task<IActionResult> BackendLoadResourceList([FromBody]FileItemSearchModel searchModel)
        {
            try
            {
                if (!ModelState.IsValid || searchModel == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                var resourceList = _businessmodelFactory.PrepareFileItemListModel(searchModel);
                return SuccessJson("", resourceList);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 删除资源
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        [HttpDelete(BackendApiRouteConfig.BackendDeleteResource)]
        public async Task<IActionResult> BackendDeleteResource([FromBody]DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                var deleteNode = _fileuploadService.GetFileUploadEntityById(node.EntityId);
                if (deleteNode == null)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);

                _fileuploadService.DeleteFileUploadEntity(deleteNode);
                deleteNode.SysLogLvl = SystemLogLevel.Information;
                deleteNode.SysLogMsg = string.Format("资源Id：{0}被删除，操作人：{1}", deleteNode.Id, _workContext.CurrentAdminUser.UserName);
                return SuccessJson(ApiResponseMessages.ResourceDeleteSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 资源添加使用layui.upload组件，上传交给upload方法，数据传输 FromForm
        /// 资源修改使用自封装httpapi,只修改资源名称属性，数据传输FormBody
        /// </summary>
        /// <param name="modeladd"></param>
        /// <param name="modeledit"></param>
        /// <returns></returns>
        [HttpPost(BackendApiRouteConfig.BackendResourceUpload)]
        public async Task<IActionResult> BackendResourceUpload([FromForm]FileItemModel modeladd)
        {
            try
            {
                if (!ModelState.IsValid || modeladd == null) throw new ArgumentNullException(ApiResponseMessages.ModelBindingError);
                if (modeladd != null && modeladd.Form.Files == null) throw new NowaException(ApiResponseMessages.NoResourceSelectForUpload);
                if (string.IsNullOrEmpty(modeladd.TitleAttribute)) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                if (modeladd != null && modeladd.StoreType == EntityEnumConfig.FileStoreType.QiniuCloud)
                {
                    if (!_nowaConfig.QiniuCloudStorageEnabled)
                        throw new NowaException(ApiResponseMessages.CloudUploadNotSupport);
                }// Default set LocalStorage
                else modeladd.StoreType = EntityEnumConfig.FileStoreType.LocalStorage;
                var retunData = new UploadResponse
                {
                    FileUploadId = 0,
                    FileUrl = ""
                };
                FileUpload fileentity = null;
                INowaFileProvider fileProvider = CommonHelper.DefaultFileProvider;
                if (modeladd.StoreType != EntityEnumConfig.FileStoreType.QiniuCloud)
                {
                    var fileExtension = fileProvider.GetFileExtension(modeladd.Form.Files[0].FileName);
                    var filetype = MimeTypes.GetSupportFileTypeByFileExt(fileExtension);
                    //var mimetype = modeladd.Form.Files[0].ContentType;
                    //if (string.IsNullOrEmpty(mimetype)) mimetype = MimeTypes.GetSupportFileMimetypeByFileExt(fileExtension);
                    var mimetype = MimeTypes.GetSupportFileMimetypeByFileExt(fileExtension);
                    if (modeladd.Id == 0)
                    {
                        fileentity = _fileuploadService.InsertFileEntity(filetype, mimetype, modeladd.Category, _fileuploadService.GetFileSeName(modeladd.Form.Files[0].FileName),
                                                    modeladd.AltAttribute, modeladd.TitleAttribute, true, "", GetFileBits(modeladd.Form.Files[0]), EntityEnumConfig.FileStoreType.LocalStorage, modeladd.LinkUrl);
                    }
                    else
                    {
                        fileentity = _fileuploadService.GetFileUploadEntityById(modeladd.Id);
                        var oldImageName = fileentity.SeoFilename;
                        if (fileentity == null) throw new NowaException(ApiResponseMessages.EntityNotFound);
                        fileentity.FileBinary = new FileBinary
                        {
                            FKFileUploadId = fileentity.Id,
                            BinaryData = GetFileBits(modeladd.Form.Files[0])
                        };
                        fileentity.SeoFilename = _fileuploadService.GetFileSeName(fileProvider.GetFileNameWithoutExtension(modeladd.Form.Files[0].FileName));
                        fileentity.FileType = filetype;
                        fileentity.IsNew = EntityEnumConfig.YesorNo.YES;
                        fileentity.MimeType = mimetype;
                        fileentity.UpdatedOnTimeUtc = DateTime.UtcNow;
                        fileentity.AltAttribute = modeladd.AltAttribute;
                        fileentity.TitleAttribute = modeladd.TitleAttribute;
                        fileentity.LinkUrl = modeladd.LinkUrl;
                        fileentity = _fileuploadService.UpdateFileEntityWithBinary(fileentity, oldImageName);
                    }
                    retunData.FileUploadId = fileentity.Id;
                    retunData.FileUrl = _fileuploadService.GetFileUrl(fileentity);
                }
                else// if (modeladd.StoreType == EntityEnumConfig.FileStoreType.QiniuCloud)
                {
                    throw new NowaException(ApiResponseMessages.CloudUploadNotSupport);
                }
                return SuccessJson(ApiResponseMessages.ResourceUploadSuccess, retunData);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [HttpPost(BackendApiRouteConfig.BackendResourceEdit)]
        public async Task<IActionResult> BackendResourceEdit([FromBody]FileItemModel modeledit)
        {
            try
            {
                if (!ModelState.IsValid || modeledit == null) throw new ArgumentNullException(ApiResponseMessages.ModelBindingError);
                if (string.IsNullOrEmpty(modeledit.TitleAttribute)) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var retunData = new UploadResponse
                {
                    FileUploadId = 0,
                    FileUrl = ""
                };
                FileUpload fileentity = null;
                fileentity = _fileuploadService.GetFileUploadEntityById(modeledit.Id);
                if (fileentity == null) throw new NowaException(ApiResponseMessages.EntityNotFound);
                fileentity.TitleAttribute = modeledit.TitleAttribute;
                fileentity.AltAttribute = modeledit.AltAttribute;
                fileentity.UpdatedOnTimeUtc = DateTime.UtcNow;
                fileentity.LinkUrl = modeledit.LinkUrl;
                fileentity = _fileuploadService.UpdateFileEntityOnly(fileentity);
                retunData.FileUploadId = fileentity.Id;
                retunData.FileUrl = _fileuploadService.GetFileUrl(fileentity);
                return SuccessJson(ApiResponseMessages.ResourceEditSuccess, retunData);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region AdvertiseManage Api
        [Route(BackendApiRouteConfig.BackendLoadAdvertiseList)]
        public async Task<IActionResult> BackendLoadAdvertiseList(int page = 0, int pagesize = 20)
        {
            try
            {
                var searchModel = new AdvertiseBannerSearchModel
                {
                    Page = page,
                    PageSize = pagesize
                };
                var advlist = _businessmodelFactory.PrepareAdvertiseBannerListModel(searchModel);
                return SuccessJson("", advlist);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpPost(BackendApiRouteConfig.BackendAdvertiseEdit)]
        public async Task<IActionResult> BackendAdvertiseEdit([FromBody]AdvertiseBannerModel modeledit)
        {
            try
            {
                if (!ModelState.IsValid || modeledit == null) throw new ArgumentNullException(ApiResponseMessages.ModelBindingError);
                if (string.IsNullOrEmpty(modeledit.AdvBannerName)) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                if((modeledit.StartTime.HasValue && !modeledit.EndTime.HasValue) 
                 || (!modeledit.StartTime.HasValue && modeledit.EndTime.HasValue))
                    throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                if(modeledit.StartTime.HasValue && modeledit.EndTime.HasValue)
                {
                    //返回值小于零：  t1 小于 t2。 返回值等于零 ： t1 等于 t2。 大于零：  t1 大于 t2。  
                    int compare = DateTime.Compare(modeledit.StartTime.Value, modeledit.EndTime.Value);
                    if (compare > 0) throw new NowaException(ApiResponseMessages.StartTimeLaterthanEndTime);
                }
                modeledit.ItemsJson = string.IsNullOrEmpty(modeledit.ItemsJson)
                                    ? null
                                    : modeledit.ItemsJson;
                var datetimeHelper = EngineContext.Current.Resolve<IDateTimeHelper>();
                Advertise entity = modeledit.ToEntity<Advertise>();
                entity.IsActive = EntityEnumConfig.YesorNo.YES;
                if (modeledit.StartTime.HasValue)
                    entity.StartTimeUtc = datetimeHelper.ConvertToUtcTime(modeledit.StartTime.Value);
                if (modeledit.EndTime.HasValue)
                    entity.EndTimeUtc = datetimeHelper.ConvertToUtcTime(modeledit.EndTime.Value);
                if (entity.Id == 0)
                {
                    entity.CreatedOnTimeUtc = DateTime.UtcNow;
                    _advertiseService.InsertAdvertise(entity);
                }
                else _advertiseService.UpdateAdvertise(entity);

                return SuccessJson(ApiResponseMessages.AdvertiseEditSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [HttpDelete(BackendApiRouteConfig.BackendDeleteAdvertise)]
        public async Task<IActionResult> BackendDeleteAdvertise([FromBody]DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                var deleteNode = _advertiseService.GetAdvertiseEntityById(node.EntityId);
                if (deleteNode == null || deleteNode.IsActive == EntityEnumConfig.YesorNo.No)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);

                deleteNode.SysLogLvl = SystemLogLevel.Information;
                deleteNode.SysLogMsg = string.Format("广告栏Id：{0}被删除，操作人：{1}", deleteNode.Id, _workContext.CurrentAdminUser.UserName);
                _advertiseService.DeleteAdvertise(deleteNode);
                return SuccessJson(ApiResponseMessages.UpdateSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region CommentManageApi
        [HttpPost(BackendApiRouteConfig.BackendLoadSystemCommentList)]
        public async Task<IActionResult> BackendLoadSystemCommentList([FromBody]CommentSearchModel searchModel)
        {
            try
            {
                if (searchModel == null) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                searchModel.EntityId = 0;
                searchModel.CommentType = EntityEnumConfig.CommentType.SystemComment;
                searchModel.CommentResponseType = EntityEnumConfig.CommentType.SystemResponse;
                var cmtList = _businessmodelFactory.PrepareCommentListModel(searchModel);
                return SuccessJson("", cmtList);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [HttpPost(BackendApiRouteConfig.BackendAddSystemCommentResponse)]
        public async Task<IActionResult> BackendAddSystemCommentResponse(int moduleid, int buttonid, [FromBody]CommentItemModel responseModel)
        {
            try
            {
                if (!_permissionService.AuthorizeModuleButton(moduleid, buttonid))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                if (responseModel == null) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var response = responseModel.ToEntity<Comment>();
                var commentItem = _commentService.GetCommentEntityById(response.RootId);
                if (commentItem == null) throw new NowaException(ApiResponseMessages.EntityNotFound);
                response.EntityId = 0;
                response.EntityName = nameof(Comment);
                response.CommentType = EntityEnumConfig.CommentType.SystemResponse;
                response.ContactName = _workContext.CurrentAdminUser.UserName;
                response.IsActive = EntityEnumConfig.YesorNo.YES;
                response.CommentIsResponsed = commentItem.CommentIsResponsed = EntityEnumConfig.YesorNo.YES;
                response.CreatedOnTimeUtc = DateTime.UtcNow;
                _commentService.AddCommentResponse(commentItem, response);
                return SuccessJson(ApiResponseMessages.SystemCommentResponseSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        [HttpDelete(BackendApiRouteConfig.BackendDeleteSystemComment)]
        public async Task<IActionResult> BackendDeleteSystemComment([FromBody]DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                var deleteNode = _commentService.GetCommentEntityById(node.EntityId);
                if (deleteNode == null || deleteNode.IsActive == EntityEnumConfig.YesorNo.No)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);

                deleteNode.SysLogLvl = SystemLogLevel.Information;
                deleteNode.SysLogMsg = string.Format("系统留言Id：{0}被删除，操作人：{1}", deleteNode.Id, _workContext.CurrentAdminUser.UserName);
                _commentService.DeleteComment(deleteNode);
                return SuccessJson(ApiResponseMessages.SystemCommentDeleteSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion
    }
}